﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management.Automation.Language;
using System.Collections;

namespace ProfilerPOC
{
    class Instrumentor : AstVisitor
    {
        // CTRL + M + O  will collapse all regions
        // CTRL + M + L will expand all

        #region Variable Declarations

        
        ScriptBlockAst ast = null;
        private string PSFile = string.Empty;
        System.Text.StringBuilder  _instrumentedScript = new StringBuilder();
        private int lineNumber = 0;
        int scriptBlockVisitCount = 0;
        const int MAXLENGTH = 25;
        ArrayList functionNames = new ArrayList();
        private static string _path;
        private static ScriptBlockAst _ast = null;

        #endregion

        #region properties

        public string Path
        {
            get { return _path; }
            set { _path = value; }
        }

        #endregion

        #region constructor

        public Instrumentor()
        {
            
        }

        public StringBuilder Script
        {
            get { return _instrumentedScript; }
        }

        #endregion


        #region General Methods

        public void InstrumentScript()
        { 
            ParseAST();
            Analyze();
        }

        public StringBuilder InstrumentedScript
        {
            get { return _instrumentedScript; }

        }

        public void ParseAST()
        {
            Token[] tok = null;
            ParseError[] err = null;


            _ast = Parser.ParseFile(_path, out tok, out err);


        }
        public void Analyze()
        {
            ast = _ast;

            AddHelperFunctionsAndVariablesToPoSHScript();

            
            ast.Visit(this);
            CloseScript();

        }

        private void AddHelperFunctionsAndVariablesToPoSHScript()
        {
            // Add PS function definition and variables needed
            _instrumentedScript.AppendLine("function Create-object($LineNum, [string]$Exp, $ExTime, $TotalExTime, $ID)" + Environment.NewLine);
            _instrumentedScript.AppendLine("{" + Environment.NewLine);
            _instrumentedScript.AppendLine("$v = New-Object System.Object" + Environment.NewLine);
            _instrumentedScript.AppendLine("$v | Add-Member -type NoteProperty -Name \"Line\" -value $LineNum" + Environment.NewLine);
            _instrumentedScript.AppendLine("$v | Add-Member -type NoteProperty -name \"Expression\" -Value $Exp.Trim(25)" + Environment.NewLine);
            _instrumentedScript.AppendLine("$v | Add-Member -type NoteProperty -Name \"Execution Time(ms)\" -Value $ExTime" + Environment.NewLine);
            _instrumentedScript.AppendLine("$v | Add-Member -type NoteProperty -Name \"Total Execution Time(ms)\" -Value $TotalExTime.TotalMilliseconds" + Environment.NewLine);
            _instrumentedScript.AppendLine("$v | Add-Member -type NoteProperty -Name \"ID\" -value $ID" + Environment.NewLine);
            _instrumentedScript.AppendLine(Environment.NewLine);
            _instrumentedScript.AppendLine("$exp = $exp.Replace(\",\",\"-\")");
            _instrumentedScript.AppendLine("write-host \"PoshProfiler: $LineNum, $Exp, $ExTime, $TotalExTime, $Id\"" + Environment.NewLine);
            _instrumentedScript.AppendLine("return $v" + Environment.NewLine);
            _instrumentedScript.AppendLine("}" + Environment.NewLine);
            _instrumentedScript.AppendLine(Environment.NewLine);
            _instrumentedScript.AppendLine("function Get-RandomID" + Environment.NewLine);
            _instrumentedScript.AppendLine("{" + Environment.NewLine);
            _instrumentedScript.AppendLine("$rnd = New-Object System.Random" + Environment.NewLine);
            _instrumentedScript.AppendLine("$rndID = $null" + Environment.NewLine);
            _instrumentedScript.AppendLine("1..5 | ForEach {$rndID = $rndID + [char]$rnd.Next(65,90)}" + Environment.NewLine);
            _instrumentedScript.AppendLine("return $rndID" + Environment.NewLine);
            _instrumentedScript.AppendLine("}" + Environment.NewLine);
            _instrumentedScript.AppendLine(Environment.NewLine);
            _instrumentedScript.AppendLine(Environment.NewLine);
            _instrumentedScript.AppendLine("$SCRIPT:IDCollection = New-Object System.Collections.ArrayList" + Environment.NewLine);
            _instrumentedScript.AppendLine(Environment.NewLine);
            _instrumentedScript.AppendLine("$SCRIPT:resultCollection = @()" + Environment.NewLine);
            _instrumentedScript.AppendLine(Environment.NewLine);
            _instrumentedScript.AppendLine("[System.Diagnostics.Stopwatch]$PoshProfiler_sw" + Environment.NewLine);
            _instrumentedScript.AppendLine("$PoshProfiler_sw = New-Object System.Diagnostics.Stopwatch" + Environment.NewLine);
            _instrumentedScript.AppendLine(Environment.NewLine);
            _instrumentedScript.AppendLine(Environment.NewLine);
            _instrumentedScript.AppendLine("start-sleep -seconds 1");
            _instrumentedScript.AppendLine("Spinning Up Now...");
            _instrumentedScript.AppendLine("gci env:");

            _instrumentedScript.AppendLine(Environment.NewLine);

        }

        private void CloseScript()
        {
            _instrumentedScript.AppendLine("Quit");
        }

        public bool CheckSpecialCases(StatementAst s)
        {

            if (s is FunctionDefinitionAst)
            {
                VisitMyFunctionDefinition(s as FunctionDefinitionAst);
                return true;
            }

            if (s is IfStatementAst)
            {
                VisitMyIfStatement(s as IfStatementAst);
                return true;
            }

            if (s is ForEachStatementAst)
            {
                VisitMyForEachStatement(s as ForEachStatementAst);
                return true;
                    
            }

            if (s is TryStatementAst)
            {
                VisitMyTryStatement(s as TryStatementAst);
                return true;

            }

            if (s is DoWhileStatementAst)
            { 
                VisitMyDoWhileStatement(s as DoWhileStatementAst);
                return true;
            }

            if (s is DoUntilStatementAst)
            {
                VisitMyDoUntilStatement(s as DoUntilStatementAst);
                return true;
            }

            if (s is WhileStatementAst)
            {
                VisitMyWhileStatement(s as WhileStatementAst);
                return true;
            }

            if (s is ForStatementAst)
            {
                VisitMyForStatement(s as ForStatementAst);
                return true;

            }

            if (s is SwitchStatementAst)
            { 
                VisitMySwitchStatement(s as SwitchStatementAst);
                return true;
            }
                          


            return false;
        }//end CheckSpecialCases()

        public bool isCallToFunction(string s)
        {
            s = s.ToLower();
            string[] elements = s.Split(' ');

            foreach (string e in elements)
            {
                if (functionNames.Contains(e))
                {
                    return true;
                }
            }

            return false;
        }

        public void BuildFunctionList(StatementAst s)
        {
            if (s is FunctionDefinitionAst)
            {
                functionNames.Add((s as FunctionDefinitionAst).Name.ToLower());
            }

        }

        private void WriteFunctionCallSnip(StatementAst s)
        {
            
            _instrumentedScript.AppendLine(s.ToString() + Environment.NewLine);
            _instrumentedScript.AppendLine("$i = ($SCRIPT:ResultCollection).ID.IndexOf($SCRIPT:IDCollection[-1])" + Environment.NewLine);
            _instrumentedScript.AppendLine("$SCRIPT:ResultCollection[$i].\'Expression\' = $SubExp" + Environment.NewLine);
            _instrumentedScript.AppendLine(String.Format("$SCRIPT:ResultCollection[$i].\'Line\' = {0}", s.Extent.StartLineNumber) + Environment.NewLine);
            _instrumentedScript.AppendLine("write-host \"PoshProfiler: \"$SCRIPT:ResultCollection[$i].Line\", \"$SCRIPT:ResultCollection[$i].Expression\", \"$SCRIPT:ResultCollection[$i].'Execution Time(ms)'\", \"$SCRIPT:ResultCollection[$i].'Total Execution Time(ms)'\", \"$SCRIPT:ResultCollection[$i].ID\"\" ");//removed \"$SCRIPT:ResultCollection[$i].'Execution Time(ms)'\",
            _instrumentedScript.AppendLine(Environment.NewLine);
            _instrumentedScript.AppendLine("$t = $SCRIPT:IDCollection[-1]" + Environment.NewLine);
            _instrumentedScript.AppendLine("$SCRIPT:IDCollection.Remove($t)" + Environment.NewLine);
        }

        private void WriteNestedStatementSnip(StatementAst s)
        {

            _instrumentedScript.AppendLine("$PoshProfiler_sw.Reset()" + Environment.NewLine);
            _instrumentedScript.AppendLine("$PoshProfiler_sw.Start()" + Environment.NewLine);
            _instrumentedScript.AppendLine(s.ToString() + Environment.NewLine);
            _instrumentedScript.AppendLine("$ExTime = $PoshProfiler_sw.Elapsed.TotalMilliseconds" + Environment.NewLine);
            _instrumentedScript.AppendLine("$script:ResultCollection[($SCRIPT:ResultCollection).ID.IndexOf($t)].'Total Execution Time(ms)' += $ExTime");
            _instrumentedScript.AppendLine(String.Format("$SCRIPT:resultCollection += Create-Object {0} $SubExp $ExTime", s.Extent.StartLineNumber) + Environment.NewLine);
            _instrumentedScript.AppendLine(Environment.NewLine);
        }

        public void WriteSnip(StatementAst s, string expression, bool InFunction)
        {


            if (s.ToString().Length > 25)
            {
                _instrumentedScript.AppendLine(String.Format("$SubExp = \'**({0}) - {1}\'", expression, s.ToString().Replace("'", "").Substring(0, MAXLENGTH)) + Environment.NewLine);
            }
            else
            {
                _instrumentedScript.AppendLine(String.Format("$SubExp = \'**({0}) - {1}\'", expression, s.ToString().Replace("'", "")) + Environment.NewLine);
            }

            if (isCallToFunction(s.Extent.Text))
            {

                WriteFunctionCallSnip(s);
                
            }
            else
            {

                if (InFunction)
                {
                    _instrumentedScript.AppendLine("$PoshProfiler_sw.Reset()" + Environment.NewLine);
                    _instrumentedScript.AppendLine("$PoshProfiler_sw.Start()" + Environment.NewLine);
                    _instrumentedScript.AppendLine(s.ToString() + Environment.NewLine);
                    _instrumentedScript.AppendLine("$ExTime = $PoshProfiler_sw.Elapsed.TotalMilliseconds" + Environment.NewLine);
                    _instrumentedScript.AppendLine("$script:ResultCollection[($SCRIPT:ResultCollection).ID.IndexOf($t)].'Total Execution Time(ms)' += $ExTime");
                    _instrumentedScript.AppendLine(String.Format("$SCRIPT:resultCollection += Create-Object {0} $SubExp $ExTime", s.Extent.StartLineNumber) + Environment.NewLine);
                    _instrumentedScript.AppendLine(Environment.NewLine);
                }
                else
                {
                    _instrumentedScript.AppendLine("$PoshProfiler_sw.Reset()" + Environment.NewLine);
                    _instrumentedScript.AppendLine("$PoshProfiler_sw.Start()" + Environment.NewLine);
                    _instrumentedScript.AppendLine(s.ToString() + Environment.NewLine);
                    _instrumentedScript.AppendLine("$ExTime = $PoshProfiler_sw.Elapsed.TotalMilliseconds" + Environment.NewLine);
                    _instrumentedScript.AppendLine(String.Format("$SCRIPT:resultCollection += Create-Object {0} $SubExp $ExTime", s.Extent.StartLineNumber) + Environment.NewLine);
                    _instrumentedScript.AppendLine(Environment.NewLine);
                }
            }

        }//end WriteSnip

        public void WriteSnip(StatementAst s, bool isNested)
        {


            if (s.ToString().Length > 25)
            {
                _instrumentedScript.AppendLine(String.Format("$SubExp = \'{0}\'", s.ToString().Substring(0, 25).Replace("'", "")) + Environment.NewLine);
            }
            else
            {
                _instrumentedScript.AppendLine(String.Format("$SubExp = \'{0}\'", s.ToString().Replace("'", "")) + Environment.NewLine);
            }
                      
            
            if (isCallToFunction(s.Extent.Text))
            {

                WriteFunctionCallSnip(s);
            }
            else if (isNested)
            {
                WriteNestedStatementSnip(s);
            }
            else
            {
                _instrumentedScript.AppendLine("$PoshProfiler_sw.Reset()" + Environment.NewLine);
                _instrumentedScript.AppendLine("$PoshProfiler_sw.Start()" + Environment.NewLine);
                _instrumentedScript.AppendLine(s.ToString() + Environment.NewLine);
                _instrumentedScript.AppendLine("$ExTime = $PoshProfiler_sw.Elapsed.TotalMilliseconds" + Environment.NewLine);
                _instrumentedScript.AppendLine(String.Format("$SCRIPT:resultCollection += Create-Object {0} $SubExp $ExTime", s.Extent.StartLineNumber) + Environment.NewLine);
                _instrumentedScript.AppendLine(Environment.NewLine);
            }
        }

        #endregion

        #region AstVisitAction Methods

        #region VisitArrayExpression
        public override AstVisitAction VisitArrayExpression(ArrayExpressionAst arrayExpressionAst)
        {
            return base.VisitArrayExpression(arrayExpressionAst);
        }
        #endregion

        #region VisitAssignmentStatement
        public override AstVisitAction VisitAssignmentStatement(AssignmentStatementAst assignmentStatementAst)
        {
            return base.VisitAssignmentStatement(assignmentStatementAst);
        }
        #endregion

        #region VisitArrayLiteral
        public override AstVisitAction VisitArrayLiteral(ArrayLiteralAst arrayLiteralAst)
        {
            return base.VisitArrayLiteral(arrayLiteralAst);
        }
        #endregion

        #region VisitAttribute
        public override AstVisitAction VisitAttribute(AttributeAst attributeAst)
        {
            return base.VisitAttribute(attributeAst);
        }
        #endregion

        #region VisitAttributedExpression
        public override AstVisitAction VisitAttributedExpression(AttributedExpressionAst attributedExpressionAst)
        {
            return base.VisitAttributedExpression(attributedExpressionAst);
        }
        #endregion

        #region VisitBinaryExpression
        public override AstVisitAction VisitBinaryExpression(BinaryExpressionAst binaryExpressionAst)
        {
            return base.VisitBinaryExpression(binaryExpressionAst);
        }
        #endregion

        #region VisitBlockStatement
        public override AstVisitAction VisitBlockStatement(BlockStatementAst blockStatementAst)
        {
            return base.VisitBlockStatement(blockStatementAst);
        }
        #endregion

        #region VisitBreakStatement
        public override AstVisitAction VisitBreakStatement(BreakStatementAst breakStatementAst)
        {
            return base.VisitBreakStatement(breakStatementAst);
        }
        #endregion

        #region VisitCatchClause
        public override AstVisitAction VisitCatchClause(CatchClauseAst catchClauseAst)
        {
            return base.VisitCatchClause(catchClauseAst);
        }
        #endregion

        #region VisitCommand
        public override AstVisitAction VisitCommand(CommandAst commandAst)
        {
            return base.VisitCommand(commandAst);
        }
        #endregion

        #region VisitCommandExpression
        public override AstVisitAction VisitCommandExpression(CommandExpressionAst commandExpressionAst)
        {
            return base.VisitCommandExpression(commandExpressionAst);
        }
        #endregion

        #region VisitCommandParameter
        public override AstVisitAction VisitCommandParameter(CommandParameterAst commandParameterAst)
        {
            return base.VisitCommandParameter(commandParameterAst);
        }
        #endregion

        #region VisitConstantExpression
        public override AstVisitAction VisitConstantExpression(ConstantExpressionAst constantExpressionAst)
        {
            return base.VisitConstantExpression(constantExpressionAst);
        }
        #endregion

        #region VisitContinueStatement
        public override AstVisitAction VisitContinueStatement(ContinueStatementAst continueStatementAst)
        {
            return base.VisitContinueStatement(continueStatementAst);
        }
        #endregion

        #region VisitConvertExpression
        public override AstVisitAction VisitConvertExpression(ConvertExpressionAst convertExpressionAst)
        {
            return base.VisitConvertExpression(convertExpressionAst);
        }
        #endregion

        #region VisitDataStatement
        public override AstVisitAction VisitDataStatement(DataStatementAst dataStatementAst)
        {
            return base.VisitDataStatement(dataStatementAst);
        }
        #endregion

        #region VisitDoUntilStatement
        public AstVisitAction VisitMyDoUntilStatement(DoUntilStatementAst doUntilStatementAst)
        {
            
            _instrumentedScript.AppendLine("Do" + Environment.NewLine);
            _instrumentedScript.AppendLine("{" + Environment.NewLine);

            foreach (StatementAst s in doUntilStatementAst.Body.Statements)
            { 
                if (CheckSpecialCases(s))
                {
                    continue;
                }
                WriteSnip(s, true);
            }
            _instrumentedScript.AppendLine(String.Format("}}Until ({0})", doUntilStatementAst.Condition) + Environment.NewLine);
                
            

            return base.VisitDoUntilStatement(doUntilStatementAst);
        }
        #endregion

        #region VisitDoWhileStatement
        public AstVisitAction VisitMyDoWhileStatement(DoWhileStatementAst doWhileStatementAst)
        {

            _instrumentedScript.AppendLine("Do" + Environment.NewLine);
            _instrumentedScript.AppendLine("{" + Environment.NewLine);

            foreach (StatementAst s in doWhileStatementAst.Body.Statements)
            {
                if (CheckSpecialCases(s))
                {
                    continue;
                }
                WriteSnip(s, true);
            }
            _instrumentedScript.AppendLine(String.Format("}}While ({0})", doWhileStatementAst.Condition) + Environment.NewLine);
                
            return base.VisitDoWhileStatement(doWhileStatementAst);
        }
        #endregion

        #region VisitErrorExpression
        public override AstVisitAction VisitErrorExpression(ErrorExpressionAst errorExpressionAst)
        {
            return base.VisitErrorExpression(errorExpressionAst);
        }
        #endregion

        #region VisitErrorStatement
        public override AstVisitAction VisitErrorStatement(ErrorStatementAst errorStatementAst)
        {
            return base.VisitErrorStatement(errorStatementAst);
        }
        #endregion

        #region VisitExitStatement
        public override AstVisitAction VisitExitStatement(ExitStatementAst exitStatementAst)
        {
            return base.VisitExitStatement(exitStatementAst);
        }
        #endregion

        #region VisitExpandableStringExpression
        public override AstVisitAction VisitExpandableStringExpression(ExpandableStringExpressionAst expandableStringExpressionAst)
        {
            return base.VisitExpandableStringExpression(expandableStringExpressionAst);
        }
        #endregion

        #region VisitFileRedirection
        public override AstVisitAction VisitFileRedirection(FileRedirectionAst redirectionAst)
        {
            return base.VisitFileRedirection(redirectionAst);
        }
        #endregion

        #region VisitForEachStatement
        public AstVisitAction VisitMyForEachStatement(ForEachStatementAst forEachStatementAst)
        {
            _instrumentedScript.AppendLine(String.Format("ForEach({0} in {1})", forEachStatementAst.Variable.ToString(), forEachStatementAst.Condition.ToString()) + Environment.NewLine);
            _instrumentedScript.AppendLine("{" + Environment.NewLine);

            foreach (StatementAst s in forEachStatementAst.Body.Statements)
            {
                if (CheckSpecialCases(s))
                {
                    continue;
                }
                WriteSnip(s, true);
            }
            _instrumentedScript.AppendLine("}" + Environment.NewLine);
            
            return base.VisitForEachStatement(forEachStatementAst);
        }
        #endregion

        #region VisitForStatement
        public AstVisitAction VisitMyForStatement(ForStatementAst forStatementAst)
        {
            _instrumentedScript.AppendLine(String.Format("For({0}; {1}; {2})", forStatementAst.Initializer, forStatementAst.Condition, forStatementAst.Iterator) + Environment.NewLine);
            _instrumentedScript.AppendLine("{" + Environment.NewLine);

            foreach (StatementAst s in forStatementAst.Body.Statements)
            {
                if (CheckSpecialCases(s))
                {
                    continue;
                }
                WriteSnip(s, true);
            }
            _instrumentedScript.AppendLine("}" + Environment.NewLine);
            

            
            return base.VisitForStatement(forStatementAst);
        }
        #endregion

        #region VisitFunctionDefinition
        public AstVisitAction VisitMyFunctionDefinition(FunctionDefinitionAst functionDefinitionAst)
        {

            _instrumentedScript.AppendLine(String.Format("Function {0}", functionDefinitionAst.Name.ToString()) + Environment.NewLine);
            _instrumentedScript.AppendLine("{" + Environment.NewLine);

            if (functionDefinitionAst.Body.ParamBlock != null)//.Parameters.Count > 0)
            { 
                _instrumentedScript.AppendLine(functionDefinitionAst.Body.ParamBlock + Environment.NewLine);
            }
            _instrumentedScript.AppendLine("$t= $null" + Environment.NewLine);
            _instrumentedScript.AppendLine("$t= Get-RandomID" + Environment.NewLine);
            _instrumentedScript.AppendLine("$SCRIPT:IDCollection.Add($t)" + Environment.NewLine);
            _instrumentedScript.AppendLine(string.Format("$SCRIPT:ResultCollection += Create-Object $null {0} $null $null $t" + Environment.NewLine, functionDefinitionAst.Name.ToString()));

            if (functionDefinitionAst.Body.EndBlock != null)
            {
                foreach (StatementAst s in functionDefinitionAst.Body.EndBlock.Statements)
                {
                    // we can have functions defined in functions. Need to test again.
                    if (CheckSpecialCases(s))
                    {
                        continue;
                    }

                    WriteSnip(s, functionDefinitionAst.Name.ToString(), true);
                   
                }
            }//end if functionDefinitionAst.Body.EndBlock != null

            _instrumentedScript.AppendLine("}" + Environment.NewLine);

            return base.VisitFunctionDefinition(functionDefinitionAst);
        }
        #endregion

        #region VisitHashtable
        public override AstVisitAction VisitHashtable(HashtableAst hashtableAst)
        {
            return base.VisitHashtable(hashtableAst);
        }
        #endregion

        #region VisitIfStatement
        public AstVisitAction VisitMyIfStatement(IfStatementAst ifStmtAst)
        {

            foreach (Tuple<PipelineBaseAst, StatementBlockAst> clause in ifStmtAst.Clauses)
            {

                _instrumentedScript.AppendLine(String.Format("if({0})", clause.Item1) + Environment.NewLine);
                _instrumentedScript.AppendLine("{" + Environment.NewLine);

                foreach (StatementAst s in clause.Item2.Statements)
                {
                    if (CheckSpecialCases(s))
                    {
                        continue;
                    }

                    WriteSnip(s, false);


                }//end foreach(clause.item2.statements)

                _instrumentedScript.AppendLine("}" + Environment.NewLine);
                
                _instrumentedScript.AppendLine(Environment.NewLine);

            }//end foreach (clause in ifStmtAst.Clauses)

            if (ifStmtAst.ElseClause != null)
            {
                _instrumentedScript.AppendLine("else" + Environment.NewLine);
                _instrumentedScript.AppendLine("{" + Environment.NewLine);

                foreach (StatementAst ec in ifStmtAst.ElseClause.Statements)
                {

                    WriteSnip(ec, false);
                    
                }

                _instrumentedScript.AppendLine("}" + Environment.NewLine);
            }
            return base.VisitIfStatement(ifStmtAst);
        }
        #endregion

        #region VisitIndexExpression
        public override AstVisitAction VisitIndexExpression(IndexExpressionAst indexExpressionAst)
        {
            return base.VisitIndexExpression(indexExpressionAst);
        }
        #endregion

        #region VisitInvokeMemberExpression
        public override AstVisitAction VisitInvokeMemberExpression(InvokeMemberExpressionAst methodCallAst)
        {
            return base.VisitInvokeMemberExpression(methodCallAst);
        }
        #endregion

        #region VisitMemberExpression
        public override AstVisitAction VisitMemberExpression(MemberExpressionAst memberExpressionAst)
        {
            return base.VisitMemberExpression(memberExpressionAst);
        }
        #endregion

        #region VisitMergingRedirection
        public override AstVisitAction VisitMergingRedirection(MergingRedirectionAst redirectionAst)
        {
            return base.VisitMergingRedirection(redirectionAst);
        }
        #endregion

        #region VisitNamedAttributeArgument
        public override AstVisitAction VisitNamedAttributeArgument(NamedAttributeArgumentAst namedAttributeArgumentAst)
        {
            return base.VisitNamedAttributeArgument(namedAttributeArgumentAst);
        }
        #endregion

        #region VisitNamedBlock
        public override AstVisitAction VisitNamedBlock(NamedBlockAst namedBlockAst)
        {
            return base.VisitNamedBlock(namedBlockAst);
        }
        #endregion

        #region VisitParamBlock
        public override AstVisitAction VisitParamBlock(ParamBlockAst paramBlockAst)
        {
            return base.VisitParamBlock(paramBlockAst);
        }
        #endregion

        #region VisitParameter
        public override AstVisitAction VisitParameter(ParameterAst parameterAst)
        {
            return base.VisitParameter(parameterAst);
        }
        #endregion

        #region VisitParentExpression
        public override AstVisitAction VisitParenExpression(ParenExpressionAst parenExpressionAst)
        {
            return base.VisitParenExpression(parenExpressionAst);
        }
        #endregion

        #region VisitPipeline
        public override AstVisitAction VisitPipeline(PipelineAst pipelineAst)
        {
            return base.VisitPipeline(pipelineAst);
        }
        #endregion

        #region VisitReturnStatement
        public override AstVisitAction VisitReturnStatement(ReturnStatementAst returnStatementAst)
        {
            return base.VisitReturnStatement(returnStatementAst);
        }
        #endregion

        #region VisitScriptBlock
        public override AstVisitAction VisitScriptBlock(ScriptBlockAst scriptBlockAst)
        {

            if (scriptBlockAst.EndBlock != null)
            {
                if (scriptBlockAst.EndBlock.Traps != null && scriptBlockAst.EndBlock.Traps.Count > 0)
                {
                    foreach (TrapStatementAst trap in scriptBlockAst.EndBlock.Traps)
                    {
                        VisitMyTrap(trap);
                    }

                }
            }

            if (scriptBlockVisitCount < 1)
            {
                scriptBlockVisitCount++;

                foreach (StatementAst s in scriptBlockAst.EndBlock.Statements)
                {
                    BuildFunctionList(s);
                }
                

                foreach (StatementAst s in scriptBlockAst.EndBlock.Statements)
                {
                    if (CheckSpecialCases(s))
                    {
                        continue;
                    }

                    WriteSnip(s, false);

                    
                }

                
            }
            return base.VisitScriptBlock(scriptBlockAst);
        }
        #endregion

        #region VisitScriptBlockExpression
        public override AstVisitAction VisitScriptBlockExpression(ScriptBlockExpressionAst scriptBlockExpressionAst)
        {
            return base.VisitScriptBlockExpression(scriptBlockExpressionAst);
        }
        #endregion

        #region VisitStatementBlock
        public override AstVisitAction VisitStatementBlock(StatementBlockAst statementBlockAst)
        {
            return base.VisitStatementBlock(statementBlockAst);
        }
        #endregion

        #region VisitStringConstantExpression
        public override AstVisitAction VisitStringConstantExpression(StringConstantExpressionAst stringConstantExpressionAst)
        {
            return base.VisitStringConstantExpression(stringConstantExpressionAst);
        }
        #endregion

        #region VisitSubExpression
        public override AstVisitAction VisitSubExpression(SubExpressionAst subExpressionAst)
        {
            return base.VisitSubExpression(subExpressionAst);
        }
        #endregion

        #region VisitSwitchStatement
        public AstVisitAction VisitMySwitchStatement(SwitchStatementAst switchStatementAst)
        {

            _instrumentedScript.AppendLine(String.Format("$SubExp = \'switch({0})\'", switchStatementAst.Condition) + Environment.NewLine);
            _instrumentedScript.AppendLine("$t= $null" + Environment.NewLine);
            _instrumentedScript.AppendLine("$t= Get-RandomID" + Environment.NewLine);
            _instrumentedScript.AppendLine("$SCRIPT:IDCollection.Add($t)" + Environment.NewLine);
            _instrumentedScript.AppendLine("$SCRIPT:ResultCollection += Create-Object $null $SubExp $null $null $t" + Environment.NewLine);
            _instrumentedScript.AppendLine(String.Format("switch({0})", switchStatementAst.Condition.ToString()) + Environment.NewLine);
            _instrumentedScript.AppendLine("{" + Environment.NewLine);
            _instrumentedScript.AppendLine(Environment.NewLine);



            foreach (Tuple<ExpressionAst, StatementBlockAst> s in switchStatementAst.Clauses)
            {
                _instrumentedScript.AppendLine(s.Item1.ToString() + Environment.NewLine);
                _instrumentedScript.AppendLine("{" + Environment.NewLine);

                foreach (StatementAst i in s.Item2.Statements)
                {
                    WriteSnip(i, true);
                }
                _instrumentedScript.AppendLine("}" + Environment.NewLine);
               
            }
            _instrumentedScript.AppendLine("}" + Environment.NewLine);
           

            return base.VisitSwitchStatement(switchStatementAst);
        }
        #endregion

        #region VisitThrowStatement
        public override AstVisitAction VisitThrowStatement(ThrowStatementAst throwStatementAst)
        {
            return base.VisitThrowStatement(throwStatementAst);
        }
        #endregion

        #region VisitTrap
        public AstVisitAction VisitMyTrap(TrapStatementAst trapStatementAst)
        {
            _instrumentedScript.AppendLine(String.Format("Trap {0}", trapStatementAst.TrapType) + Environment.NewLine);
            _instrumentedScript.AppendLine("{" + Environment.NewLine);

            foreach (StatementAst s in trapStatementAst.Body.Statements)
            {
                _instrumentedScript.AppendLine(s.ToString() + Environment.NewLine);
            }

            _instrumentedScript.AppendLine("}" + Environment.NewLine + Environment.NewLine);
            
            return base.VisitTrap(trapStatementAst);
        }
        #endregion

        #region VisitTryStatement
        public AstVisitAction VisitMyTryStatement(TryStatementAst tryStatementAst)
        {
            _instrumentedScript.AppendLine("try{" + Environment.NewLine);

            foreach (StatementAst s in tryStatementAst.Body.Statements)
            {
                lineNumber = s.Extent.StartLineNumber;

                WriteSnip(s, false);
               

            }//end foreach body.statements

            _instrumentedScript.AppendLine("}" + Environment.NewLine);

            foreach (CatchClauseAst c in tryStatementAst.CatchClauses)
            {

                if (c.CatchTypes.Count > 1)
                {
                    string exceptionList = null;
                    for (int i = 0; i < c.CatchTypes.Count; i++)
                    {
                        exceptionList += c.CatchTypes[i].ToString() + " ,";
                    }
                    //remove last comma
                    exceptionList.TrimEnd(',');

                    _instrumentedScript.AppendLine(String.Format("catch {0}", exceptionList) + Environment.NewLine);

                }
                else if (c.CatchTypes.Count != 0)
                {
                    _instrumentedScript.AppendLine(String.Format("catch {0}", c.CatchTypes[0]) + Environment.NewLine);
                }
                else
                {
                    _instrumentedScript.AppendLine("catch" + Environment.NewLine);
                }

                _instrumentedScript.AppendLine("{" + Environment.NewLine);
                _instrumentedScript.AppendLine("$ExTime = $PoshProfiler_sw.Elapsed.TotalMilliseconds" + Environment.NewLine);
                _instrumentedScript.AppendLine(String.Format("$SCRIPT:resultCollection += Create-Object {0} $SubExp $ExTime", lineNumber) + Environment.NewLine);

                foreach (StatementAst bodyStmt in c.Body.Statements)
                {
                    if (CheckSpecialCases(bodyStmt))
                    {
                        continue;
                    }

                    WriteSnip(bodyStmt, false);
                   
                }//end foreach (body in statements


                _instrumentedScript.AppendLine("}" + Environment.NewLine);
            }//end foreach (c in catchclauses)

            
            return base.VisitTryStatement(tryStatementAst);
        }
        #endregion

        #region VisitTypeConstraint
        public override AstVisitAction VisitTypeConstraint(TypeConstraintAst typeConstraintAst)
        {
            return base.VisitTypeConstraint(typeConstraintAst);
        }
        #endregion

        #region VisitTypeExpression
        public override AstVisitAction VisitTypeExpression(TypeExpressionAst typeExpressionAst)
        {
            return base.VisitTypeExpression(typeExpressionAst);
        }
        #endregion

        #region VisitUnaryExpression
        public override AstVisitAction VisitUnaryExpression(UnaryExpressionAst unaryExpressionAst)
        {
            return base.VisitUnaryExpression(unaryExpressionAst);
        }
        #endregion

        #region VisitUsingExpression
        public override AstVisitAction VisitUsingExpression(UsingExpressionAst usingExpressionAst)
        {
            return base.VisitUsingExpression(usingExpressionAst);
        }
        #endregion

        #region VisitVariableExpression
        public override AstVisitAction VisitVariableExpression(VariableExpressionAst variableExpressionAst)
        {
            return base.VisitVariableExpression(variableExpressionAst);
        }
        #endregion

        #region VisitWhileStatement
        public AstVisitAction VisitMyWhileStatement(WhileStatementAst whileStatementAst)
        {
            _instrumentedScript.AppendLine(String.Format("While({0})", whileStatementAst.Condition) + Environment.NewLine);
            _instrumentedScript.AppendLine("{" + Environment.NewLine);

            foreach (StatementAst s in whileStatementAst.Body.Statements)
            {
                if (CheckSpecialCases(s))
                {
                    continue;
                }

                WriteSnip(s, false);
            }
            _instrumentedScript.AppendLine("}" + Environment.NewLine);
            
            return base.VisitWhileStatement(whileStatementAst);
        }
        #endregion

        #endregion
    }
}
